<template>

  <div v-on:click="test22">12312313</div>
  <button @click="reactiveOnClick">改变解构值</button>
  <div>{{ reactiveData }}---</div>
  <div>{{ reactiveDataName }}---</div>
  <div>{{ reactiveDataMsg }}-</div>
  <div>{{ reactiveDataName2 }}</div>
  <div>{{ reactiveDataNameToRef }}</div>

</template>
<script setup lang="ts">
import { defineComponent, reactive, ref, watchEffect, watch, toRef } from 'vue';
import YcDialog from "@/widget/dialog/YcLoading.vue"

const test22 = () => {
  // YcDialog.showLoading()
}
class Data2 {
  name: string
  constructor(name: string) {
    this.name = name
  }
}
let testData: Number = 1
let data = new Data2(String(testData.toString))
console.log(data);

console.log(String(null));

interface ITest {
  x: number
  y: number
  zxy: number
}
function testI(testData: ITest, key: "x" | "y" | "zxy"): number {
  console.log(testData[key]);

  return testData[key]
}
let testData1 = { x: 10, y: 12, zxy: 212 }
// let testKey = "x"
// testI(testData1, testKey)

const testKey2 = "x"
testI(testData1, testKey2)

let testKey3 = "x" as const //const 断言
testI(testData1, testKey3)

testI({ x: 10, y: 12, zxy: 212 }, "x")



let func = (anything: any) => {
  if (typeof anything === 'string') {
    return anything; // 类型是 string 
  } else if (typeof anything === 'number') {
    return anything; // 类型是 number
  }
  return null;
};
//类型别名
type TypeMore = string | number;//联合类型
function testFun2(typeData: TypeMore) {
  switch (typeof typeData) {
    case 'string':
      console.log(typeData, "是string类型");
      break
    case 'number':
      console.log(typeData, "是number类型");
      break
    default:
      console.log(typeData, "是未知类型");
  }
}
testFun2(123)
testFun2("字符串")

type TypeMore2 = string & number//交叉类型
type TypeSingle1 = { name: string, sameName: string }
type TypeSingle2 = { id: number, sameName: string }
type TypeMore3 = TypeSingle1 & TypeSingle2
let typeMore2: TypeMore3 = { name: "12", id: 321, sameName: "123" }

// 接口可以定义多次,类型别名不可以;接口可以定义多次，会被自动合并为单个接口
interface IPoint {
  x: number
}
interface IPoint {
  y: number
}

let point: IPoint = { x: 1, y: 2 }

//解构 结果为对象保留响应式，原始类型无响应效果；原因：对象是引用，原始类型是赋值
let reactiveData = reactive({ reactiveDataName: "名字", reactiveDataMsg: { reactiveDataName2: "名字2：" } })
let { reactiveDataName, reactiveDataMsg } = reactiveData
let { reactiveDataName2 } = reactiveData.reactiveDataMsg
let reactiveDataNameToRef = toRef(reactiveData, "reactiveDataName")
let reactiveDataMsgToRef = toRef(reactiveData, "reactiveDataMsg")
let addData = 1
const reactiveOnClick = () => {
  // reactiveData.reactiveDataName += `[${addData}]`
  reactiveDataName += `[${addData}]` //无响应效果
  reactiveDataMsg.reactiveDataName2 += `[${addData}]`//有响应式效果
  reactiveDataName2 += `[${addData}]`//无响应式效果
  reactiveDataNameToRef.value += `[${addData}]`
  reactiveDataMsgToRef.value.reactiveDataName2 += `[${addData}]`
  addData++
  console.log("111");

}

/**
 * keyof 用于获取某种类型的所有键，其返回类型是联合类型
 */
interface IKeyOf {
  name: string;
  id: string;
}
type keys = keyof IKeyOf;
// K extends keyof T 限制 T 只能是 K 的属性名
function getValue2<T extends Object, K extends keyof T>(ob: T, key: K): T[K] {
  return ob[key];
}
const data111: IKeyOf = { name: "张三", id: "123" }
// getValue2(data111, "123") //报错
getValue2(data111, "name")

interface Person2 {
  name: string;
  age: number;
  location: string;
}

type K1 = keyof Person2; // "name" | "age" | "location"
type K2 = keyof Person2[];  // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person2 };  // string | number


/**
 * in用于取联合类型的值。主要用于数组和对象的构造。不要用于 interface，否则会出错
 */
type Item = { a: string; b: number; c: boolean };

type T21 = { [P in "x" | "y"]: number }; // { x: number, y: number }
type T22 = { [P in "x" | "y"]: P }; // { x: "x", y: "y" }
type T23 = { [P in "a" | "b"]: Item[P] }; // { a: string, b: number }
type T24 = { [P in keyof Item]: Item[P] }; // { a: string, b: number, c: boolean }
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};

interface Person {
  name: string;
  age: number;
  location: string;
}

type LazyPerson = Getters<Person>;
/**
 * infer 占位符式的关键字
 * 表示在 extends 条件语句中以占位符出现的用来修饰数据类型的关键字，被修饰的数据类型等用到的时候才能被推断出来
 */
type InferType<T> = T extends (prams: infer P) => any ? P : T

interface Dictionary<T> {
  [key: string]: T;
}
type StrDict = Dictionary<string>
type DictMember<T> = T extends Dictionary<infer V> ? V : never
type StrDictMember = DictMember<StrDict> // string



interface Person {
  name: string;
  age: number;
}
async function stringPromise() {
  return "Hello, 1231!";
}
async function personPromise(data: any[]) {
  return { name: "1231", age: 30 } as Person;
}
type PromiseType<T> = (args: any[]) => Promise<T>;
type UnPromisify<T> = T extends PromiseType<infer U> ? U : never;
type TStr = typeof stringPromise
type TPerson = typeof personPromise
type extractStringPromise = UnPromisify<TStr>; // string
type extractPersonPromise = UnPromisify<TPerson>; // Person


interface Todo {
  title: string;
  description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}

const todo1 = {
  title: "organize desk",
  description: "clear clutter"
};

const todo2 = updateTodo(todo1, {
  description: "throw out trash"
});


/**
 * Record  的作用是将 K 中所有的属性的值转化为 T 类型
 * type Record<K extends keyof any, T> = {
 *   [P in K]: T;
 * };
 */

interface PageInfo {
  title: string;
  name: string
}

type Page = "home" | "about" | "contact";
type TRecord = Record<Page, PageInfo>
const x: TRecord = {
  about: { title: "about", name: "1" },
  contact: { title: "contact", name: "2" },
  home: { title: "home", name: "3" }
};

/**
 * Pick  将某个类型中的子属性挑出来，变成包含这个类型部分属性的子类型。
 * type Pick<T, K extends keyof T> = {
 *   [P in K]: T[P];
 * };
 */
 interface Todo2 {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo2, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false
};

/**
 * Exclude  将某个类型中属于另一个的类型移除掉。
 * type Exclude<T, U> = T extends U ? never : T;
 */

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number

  
/**
 * ReturnType  将某个类型中属于另一个的类型移除掉。
 * type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
 */
type T10 = ReturnType<() => string>; // string
type T11 = ReturnType<(s: string) => void>; // void
type T12 = ReturnType<<T>() => T>; // {}
type T13 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T14 = ReturnType<any>; // any
type T15 = ReturnType<never>; // any
// type T16 = ReturnType<string>; // Error
// type T17 = ReturnType<Function>; // Error


/**
 * 构造签名
 */
interface IConstructor{
  new (x:number,y:string):IConstructor
}
// // 构造函数类型字面量
// new (x: number, y: number) => IConstructor
// // 等价于对象类型字面量
// {
//   new (x: number, y: number): IConstructor;
// }
class GenericCreator<T> {
  create<T>(c: { new(name: string): T }, name: string): T {
    return new c(name);
  }
}
interface IClass3{
  name2: string
}
class Class1{
  name1:string
  constructor(name:string){
    this.name1 = name
  }
}
class Class2{
  name2: string
  constructor(name: string) {
    this.name2 = name
  }
}
const creator1 = new GenericCreator<Class1>();
const firstClass: Class1 = creator1.create(Class1,"张三");

const creator2 = new GenericCreator<Class2>();
const secondClass: Class2 = creator2.create(Class2, "张三");


// const creator3 = new GenericCreator<IClass3>();
// const class3: IClass3 = creator3.create(IClass3,"123");

interface IData<T> {
  name: T,
  id: string
}
let mIData: IData<number> = {
  name: 1,
  id: "123"
}
console.log(mIData);
const name = 23;
let id2 = "1222"
//变量名和接口定义的变量名一样时可以简写
let mIData2: IData<number> = {
  name,
  id: id2
}
console.log(mIData2);

</script>